﻿using Assets.Scripts.DL.ComponentScripts;
using Assets.Scripts.DL.Consts;
using Assets.Scripts.DL.Enemy.BaseClass.FSM;
using Assets.Scripts.DL.Enemy.CommonEnemy;
using Assets.Scripts.DL.Enemy.CommonEnemy.States;
using Assets.Scripts.DL.Enemy.CommonEnemy.States.ATK;
using Assets.Scripts.DL.Enemy.CommonEnemy.States.CommonState;
using Assets.Scripts.DL.Enemy.CommonEnemy.States.Special;
using Assets.Scripts.DL.Mgrs;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem.XR;
using UnityEngine.U2D;

namespace Assets.Scripts.DL.Enemy.SpriderBoss {
	public class SpiderBossController : Controller {
		public AudioSource StateAudio;
		public Material InjuredMat;
		public Material LitMat;
		[Header("Debug")]
		//public bool atk1;
		//public bool atk2;
		//public float atk3time;
		//public float atk4time;
		public Vector2 DICIOffset;
		public float DiciDisGap = 0.5f;
		public float DiciTimeGap = 0.5f;

		[Tooltip("用于运行时获取玩家位置")]
		public GameObject Player;
		public SpriteRenderer sprite;

		[Header("Time")]
		public int CureTime = 5;

		[Header("AtkOffset")]
		public Vector2 Atk1Off;
		public Vector2 Atk2Off;
		public Vector2 Atk3Off;
		public Vector2 Atk3GroundOff;

		[Header("AtkDamage")]
		public int Atk1Dmg;
		public int Atk2Dmg;
		public int Atk3Dmg;
		//Atk3偏移为0，因为从自身发起攻击
		//Atk4不是自身发攻击，所以没有Off和range
		[Header("AtkRange")]
		public float Atk1Range;
		public float Atk2Range;
		public float Atk3Range;

		[Header("AtkCd")]
		public int JumpFallCd = 5;//atk3
		[Tooltip("弹幕Cd")]
		public int BarrageCd = 10;

		[Header("AtkTimes")]
		[Tooltip("弹幕方向数量")]
		public int BarrageDirCnts;
		[Tooltip("一次发送几波弹幕")]
		public int BarrageTimes;

		[Header("AnimNormalizeTime")]
		public float Atk1NormalTime = 0.9f;
		public float Atk2NormalTime = 0.6f;
		public float JumpNormalTime = 0.9f;
		public float BarrageNormalTime = 0.9f;

		[Header("Speed")]
		public int JumpSpeed;
		public int FallSpeed;
		public int BarrageSpeed;

		[Header("Position")]
		public float MaxJumpHeight;
		public float BarrageDisFromCenter;//和boss中心的距离
		public float BarrageYOffset;//Y方向调整，防止角色太矮达不到

		[Header("Other")]
		public int CureHp = 50;
		public bool IsCured = false;
		public bool ShoudCure = false;
		protected override void InitAnimMgr() {
			//base.InitAnimMgr();
			AddAnim(StateEnum.Idle, "Idle");
			AddAnim(StateEnum.Move, "Move");
			AddAnim(StateEnum.Atk1, "Atk1");
			AddAnim(StateEnum.Atk2, "Atk2");
			AddAnim(StateEnum.ReadyJump, "ReadyJump");
			AddAnim(StateEnum.Jump, "Jump");
			AddAnim(StateEnum.FallOnGround, "FallOnGround");
			AddAnim(StateEnum.Fall, "Fall");
			AddAnim(StateEnum.Atk4, "Steam");//喷气或者治疗都是这个动作
			AddAnim(StateEnum.Hurt, "Hurt");
			AddAnim(StateEnum.Die, "Die");
		}
		protected override void InitStates() {
			//一般状态
			var commonHfsm = new SpiderBossCommonHFSM(this, StateEnum.CommonHFSM);
			var move = new SpiderBossMove(this, StateEnum.Move);
			var idle = new Idle(this, StateEnum.Idle);
			commonHfsm.InitSubStates(new Dictionary<StateEnum, EnemyState<StateEnum>> {
				{StateEnum.Idle, idle},
				{StateEnum.Move, move},
				}
			);

			//Atk
			var atkHFSM = new AtkHFSM(this, StateEnum.AtkHFSM);
			//Atk1-4
			var atk1 = new SpiderBossCommonAtk(this, StateEnum.Atk1);//距离较近
			atk1.AddConditionToSelf(
				() => IsPlayerInAtkRange(Atk1Off.sqrMagnitude)
			);
			var atk2 = new SpiderBossCommonAtk(this, StateEnum.Atk2);
			atk2.AddConditionToSelf(
				() => !IsPlayerInAtkRange(Atk1Off.sqrMagnitude) && IsPlayerInAtkRange(Atk2Off.sqrMagnitude)
			);
			var atk3 = new SpiderBossJumpFallAtk(this, StateEnum.Atk3);
			var atk4 = new SpiderBossBarrageAtk(this, StateEnum.Atk4);
			atkHFSM.InitSubStates(new Dictionary<StateEnum, EnemyState<StateEnum>> {
				{ StateEnum.Atk1, atk1 },
				{ StateEnum.Atk2, atk2 },
				{ StateEnum.Atk3, atk3 },
				{ StateEnum.Atk4, atk4},
			});


			//Special
			//差一个Cure！！！！！！！！！！！！！！！！！！！！！！！！
			var specialHFSM = new EnemySpecialHFSM(this, StateEnum.SpecialHFSM);
			//specialHFSM.AddConditionToSelf(() =>);
			var hurt = new Hurt(this, StateEnum.Hurt);
			hurt.AddConditionToSelf(() => !ShoudCure);
			var die = new Die(this, StateEnum.Die);
			var cure = new SpiderBossCure(this, StateEnum.Cure);
			specialHFSM.InitSubStates(new Dictionary<StateEnum, EnemyState<StateEnum>> {
				{ StateEnum.Die, die },{StateEnum.Hurt, hurt },{StateEnum.Cure,cure},
			}
			);

			//Root
			_rootHFSM.InitSubStates(new Dictionary<StateEnum, EnemyState<StateEnum>> {
				{StateEnum.CommonHFSM,  commonHfsm},
				{StateEnum.AtkHFSM,  atkHFSM},
				{StateEnum.SpecialHFSM, specialHFSM },
				}
			);
		}

		protected override void InitAtkTimer() {
			//base.InitAtkTimer();
			StateData.AtkCdRecoder = new Dictionary<StateEnum, Timer> {
				{StateEnum.Atk1, new Timer() },//atk12用一个
				{StateEnum.Atk3, new Timer() },
				{StateEnum.Atk4, new Timer() },
			};
		}

		public override Vector3 GetPlayerPos()
			=> Player.transform.position;

		//普攻
		public override bool CanAtk() {
			return StateData.AtkCdRecoder[StateEnum.Atk1].Elapsed > Config.EachAtkGap;
		}

		//满足较远的普攻范围
		public override bool IsPlayerInAtkRange() {
			//计算直线范围
			return IsPlayerInAtkRange(Atk2Off.sqrMagnitude);
			//var ret = Player != null &&
			//  RayDetect(GetRealXDirPos(Atk2Off), Atk2Range, GetFaceDirVec(), GetLayer(LayerStrings.Player));
			////Debug.Log(ret);
			//return ret;
		}

		public bool IsPlayerInAtkRange(float offSqr) {
			if (Player == null) {
				return false;
			}
			var cur = transform.position;
			var p = Player.transform.position;
			return (cur - p).sqrMagnitude < offSqr;
		}

		public bool IsPlayerInAtkRange(Vector2 off, float range)
			=> Player != null && RayDetect(GetRealXDirPos(off), range, GetFaceDirVec(), GetLayer(LayerStrings.Player));

		//由当前位置xy坐标，最高高度，玩家x坐标计算
		public Vector2 GetFinalJumpPosDir() {
			var curp = (Vector2)transform.position;
			var ret = new Vector2(Player.transform.position.x - curp.x, MaxJumpHeight - curp.y);
			return ret.normalized;
		}

		//判断有没有到达某个位置，用于跳跃，根据高度和玩家x坐标决定
		public bool IsAtPos(float x, float y) {
			return IsTransNear(transform.position.x, x) && IsTransNear(transform.position.y, y);
		}

		public bool IsTransNear(float a, float b) {
			return Mathf.Abs(a - b) < 1;
		}
		////很不优雅
		public override bool CheckSpecialCd() {
			if (Player == null)
				return false;
			var cdDic = StateData.AtkCdRecoder;
			var cd3 = cdDic[StateEnum.Atk3].Elapsed > JumpFallCd;
			var cd4 = cdDic[StateEnum.Atk4].Elapsed > BarrageCd;
			return cd3 || cd4;
		}

		public override void TakeDamage(int damage) {
			base.TakeDamage(damage);
			//if (!StateData.IsHurt)//非受伤动画
			//sprite.color = Color.red;
			if (StateData.CurHP < Config.MaxHP / 2 && !IsCured) {
				StateData.IsSpecialState = true;
				ShoudCure = true;
				//Debug.Log("Special");
			}
			StartCoroutine(ChangeSpriteColor(Color.red, 0.3f));
		}

		IEnumerator ChangeSpriteColor(Color c, float sec) {
			//var origin = sprite.material;
			sprite.material = InjuredMat;
			InjuredMat.SetColor("_InjuredColor", c);
			yield return new WaitForSeconds(sec);
			InjuredMat.SetColor("_InjuredColor", Color.clear);
			sprite.material = LitMat;
		}

		Vector3 GetRealPos(Vector2 off) {
			Vector3 p = transform.position;
			var dir = transform.localScale.x;
			var realOffset = new Vector3(off.x * dir, off.y, 0);
			return p + realOffset;
		}
		protected override void Update() {
			base.Update();
			//if (Input.GetKeyDown(KeyCode.F)) {
			//	var obj = ObjectPool.Instance.GetObject(ObjPoolStr.DiCi);
			//	obj.GetComponent<DiCi>().Init(transform.position + (Vector3)DICIOffset);
			//}
			//atk1 = IsPlayerInAtkRange(Atk1Off, Atk1Range);
			//atk2 = IsPlayerInAtkRange(Atk2Off, Atk2Range);
			//atk3time = StateData.AtkCdRecoder[StateEnum.Atk3].Elapsed;
			//atk4time = StateData.AtkCdRecoder[StateEnum.Atk4].Elapsed;
		}
		private void OnDrawGizmos() {
			Vector3 p = transform.position;
			var dir = transform.localScale.x;
			Func<Vector2, Vector3> getpos = (offset) => {
				var realOffset = new Vector3(offset.x * dir, offset.y, 0);
				return p + realOffset;
			};
			Gizmos.DrawWireSphere(getpos(Atk1Off), Atk1Range);
			Gizmos.DrawWireSphere(getpos(Atk2Off), Atk2Range);
			Gizmos.DrawWireSphere(getpos(Atk3Off), Atk3Range);
			Gizmos.DrawWireSphere(getpos(Atk3GroundOff), Atk3Range);

			//Gizmos.DrawWireSphere(getpos(), );
		}
	}
}
